<?php

/**
 * 短链接生成类
 */
class ShortUrl {

    //数据库类型
    public $dbType = 'mysql';
    //当前连接ID
    private $connectId = null;
    //操作所影响的行数
    private $affectedRows = 0;
    //查询结果对象
    private $PDOStatement = null;

    public function __construct($config='') {
        if (!class_exists('PDO')) {
            die('Not Support : PDO');
        }
        $this->config = $config;
    }

    /**
     * 类的析构方法(负责资源的清理工作)
     */
    public function __destruct() {
        $this->dbType = null;
        $this->connectId = null;
        $this->PDOStatement = null;
    }

    /**
     * 打开数据库连接
     */
    private function connect() {
        if ($this->connectId == null) {
            if (empty($this->config)) {
                die("数据库配置文件不存在!");
            }
            $this->connectId = new PDO("mysql:host={$this->config['host']};dbname={$this->config['db']}", $this->config['user'], $this->config['password']);
            $this->connectId->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //打开PDO错误提示
            if ($this->dbType == 'mysql') {
                $this->connectId->exec("set names utf8");
            }
            $dsn = $username = $password = $encode = null;
            if ($this->connectId == null) {
                die("PDO CONNECT ERROR");
            }
        }
    }


    /**
     * 释放查询结果
     */
    private function free() {
        $this->PDOStatement = null;
    }

    /**
     * 执行语句 针对 INSERT, UPDATE 以及DELETE
     * @access public 
     * @param string $sql  sql指令
     * @return boolean
     */
    public function query($sql) {
        if ($this->connectId == null) {
            $this->connect();
        }
        $this->affectedRows = $this->connectId->exec($sql);
        return $this->affectedRows >= 0 ? true : false;
    }

    /**
     * 获得一条查询记录
     * @access public 
     * @param string  $sql  SQL指令
     * @return array
     */
    public function find_url($code='',$table='') {
        if ($this->connectId == null) {
            $this->connect();
        }
        $id = $this->b64to10($code);
        $result = array();   //返回数据集
        $sql = "select * from {$table} where id='{$id}'";
        $this->PDOStatement = $this->connectId->prepare($sql);
        $this->PDOStatement->execute();

        $result = $this->PDOStatement->fetch(constant('PDO::FETCH_ASSOC'));
        $this->free();
        if(!empty($result)) return $result['url'];
    }

   
   /**
    * 生成短链接
    * @param type $table 表名
    * @param type $arr 插入的数据
    * @param type $url 短链接前缀
    * @return string
    */
    public function generate_url($table, $arr = array(),$url='') {
        $field = $value = $short_url = "";
        if (!empty($arr) && is_array($arr)) {
            foreach ($arr as $k => $v) {
                $v = preg_replace("/'/", "\\'", $v);
                $field .= "$k,";
                $value .= "'$v',";
            }
            $field = preg_replace("/,$/", "", $field);
            $value = preg_replace("/,$/", "", $value);
            $sql = "INSERT INTO $table($field) VALUES($value)";
            $this->query($sql);
            $last_id = $this->getLastInsId();
            $url_code = $this->b10to64($last_id);
            if(!empty($url_code)){
                $short_url = $url.'/'.$url_code;
            }
            return $short_url;
        }
    }

    /**
     * 返回最后一次使用 INSERT 指令的 ID
     */
    public function getLastInsId() {
        if ($this->connectId != null) {
            return $this->connectId->lastInsertId();
        }
        return 0;
    }

    /**
     * 64进制转换成10进制
     * @param type $b64
     * @return boolean
     */
    function b64to10($b64) { //64进制转换成10进制
        $map = array(
            '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9,
            'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 'E' => 14, 'F' => 15, 'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19,
            'K' => 20, 'L' => 21, 'M' => 22, 'N' => 23, 'O' => 24, 'P' => 25, 'Q' => 26, 'R' => 27, 'S' => 28, 'T' => 29,
            'U' => 30, 'V' => 31, 'W' => 32, 'X' => 33, 'Y' => 34, 'Z' => 35, 'a' => 36, 'b' => 37, 'c' => 38, 'd' => 39,
            'e' => 40, 'f' => 41, 'g' => 42, 'h' => 43, 'i' => 44, 'j' => 45, 'k' => 46, 'l' => 47, 'm' => 48, 'n' => 49,
            'o' => 50, 'p' => 51, 'q' => 52, 'r' => 53, 's' => 54, 't' => 55, 'u' => 56, 'v' => 57, 'w' => 58, 'x' => 59,
            'y' => 60, 'z' => 61, '_' => 62, '=' => 63
        );
        $dec = 0;
        $len = strlen($b64);
        for ($i = 0; $i < $len; $i++) {
            $b = $map[$b64{$i}];
            if ($b === null) {
                return false;
            }
            $j = $len - $i - 1;
            $dec += ($j == 0 ? $b : (2 << (6 * $j - 1)) * $b);
        }
        return $dec;
    }

    /**
     * 10进制转换成64进制
     * @param int $dec
     * @return boolean|string
     */
    function b10to64($dec) {
        if ($dec < 0)
            return false;
        $map = array(
            0 => '0', 1 => '1', 2 => '2', 3 => '3', 4 => '4', 5 => '5', 6 => '6', 7 => '7', 8 => '8', 9 => '9',
            10 => 'A', 11 => 'B', 12 => 'C', 13 => 'D', 14 => 'E', 15 => 'F', 16 => 'G', 17 => 'H', 18 => 'I', 19 => 'J',
            20 => 'K', 21 => 'L', 22 => 'M', 23 => 'N', 24 => 'O', 25 => 'P', 26 => 'Q', 27 => 'R', 28 => 'S', 29 => 'T',
            30 => 'U', 31 => 'V', 32 => 'W', 33 => 'X', 34 => 'Y', 35 => 'Z', 36 => 'a', 37 => 'b', 38 => 'c', 39 => 'd',
            40 => 'e', 41 => 'f', 42 => 'g', 43 => 'h', 44 => 'i', 45 => 'j', 46 => 'k', 47 => 'l', 48 => 'm', 49 => 'n',
            50 => 'o', 51 => 'p', 52 => 'q', 53 => 'r', 54 => 's', 55 => 't', 56 => 'u', 57 => 'v', 58 => 'w', 59 => 'x',
            60 => 'y', 61 => 'z', 62 => '_', 63 => '=',
        );
        $b64 = '';
        do {
            $b64 = $map[($dec % 64)] . $b64;
            $dec /= 64;
        } while ($dec >= 1);
        return $b64;
    }

}

